﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoachingOrganizer.Database.DataAccess;
using CoachingOrganizer.Database.DataAccessLayer.Tools.MoneyCalculation;
using CoachingOrganizer.Database.DataAccessLayer.Tools.MoodLevel;
using CoachingOrganizer.Database.DataAccessLayer.Tools.EmotionsPack;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage;
using CoachingOrganizer.Toolkit.Events;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.MoodLevel;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.MoneyCalculation;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.EmotionsPack;

namespace CoachingOrganizer.Database.DataAccessLayer
{
    public class GoalDAL : IGoalInfo
    {
        private readonly DbManagerBase _dbManager;
        private readonly List<ToolDALBase> _tools = new List<ToolDALBase>();
        private GoalDA _da;
        private string _title;
        private string _description;
        private string _expectedResultVolume;

        public List<ToolDALBase> Tools
        {
            get { return _tools; }
        }

        public IEnumerable<IToolInfo> ToolsInfo
        {
            get { return _tools; }
        }

        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }

        public string Description
        {
            get { return _description; }
            set { _description = value; }
        }

        public string ExpectedResultVolume
        {
            get { return _expectedResultVolume; }
            set { _expectedResultVolume = value; }
        }

        public GoalDAL(DbManagerBase dbManager)
        {
            _dbManager = dbManager;
        }

        public GoalDA CreateNewDA(PeriodDA period)
        {
            return _da = new GoalDA
            {
                Title = _title,
                PeriodId = period.Id
            };
        }

        public ActionResult Save()
        {
            _da.Title = _title;
            _da.Description = _description;
            _da.ExpectedResultVolume = _expectedResultVolume;
            return _dbManager.SafeRun(() => _dbManager.Context.InsertOrReplace(_da));
        }

        public bool Load(int id)
        {
            GoalDA goal = _dbManager.Context.Find<GoalDA>(da => da.Id == id);
            if (goal == null)
                return false;
            Load(goal);
            return true;
        }

        public void Load(GoalDA goal)
        {
            _da = goal;
            _title = _da.Title;
            _description = _da.Description;
            _expectedResultVolume = _da.ExpectedResultVolume;
            LoadTools();
        }

        public ActionResult Remove()
        {
            if (_da != null)
                return _dbManager.SafeRun(() => _dbManager.Context.Delete<GoalDA>(_da.Id));
            return ActionResult.GetErrorResult(new KeyNotFoundException());
        }

        public ActionResult<TToolInfo> AddNewTool<TToolInfo>(Action<TToolInfo> initCallback) where TToolInfo : IToolInfo
        {
            TToolInfo newTool;
            if (typeof(TToolInfo) == typeof(IMoodLevelInfo))
                newTool = (TToolInfo)(IToolInfo)CreateNewMoodLevel();
            else if (typeof(TToolInfo) == typeof(IMoneyCalculationInfo))
                newTool = (TToolInfo)(IToolInfo)CreateNewMoneyCalculation();
            else if (typeof(TToolInfo) == typeof(IEmotionsPackInfo))
                newTool = (TToolInfo)(IToolInfo)CreateNewEmotionsPack();
            else
                throw new NotImplementedException();
            if (initCallback != null)
                initCallback(newTool);
            ActionResult addResult = AddTool((ToolDALBase)(IToolInfo)newTool);
            return addResult.IsValid ? ActionResult<TToolInfo>.GetValidResult(newTool) : ActionResult<TToolInfo>.GetErrorResult(addResult);
        }

        public MoodLevelDAL CreateNewMoodLevel()
        {
            return new MoodLevelDAL(_dbManager);
        }

        public EmotionsPackDAL CreateNewEmotionsPack()
        {
            return new EmotionsPackDAL(_dbManager);
        }

        public MoneyCalculationDAL CreateNewMoneyCalculation()
        {
            return new MoneyCalculationDAL(_dbManager);
        }

        public ActionResult AddTool(ToolDALBase tool)
        {
            _tools.Add(tool);
            return _dbManager.SafeRun(() => _dbManager.Context.Insert(tool.CreateNewDA(_da)));
        }

        public ActionResult LoadTools()
        {
            return _dbManager.SafeRun(() =>
            {
                foreach (MoodLevelDA moodChartDA in _dbManager.Context.Table<MoodLevelDA>().Where(g => g.GoalId == _da.Id).ToArray())
                {
                    MoodLevelDAL moodChart = new MoodLevelDAL(_dbManager);
                    moodChart.Load(moodChartDA);
                    _tools.Add(moodChart);
                }
                foreach (EmotionsPackDA emotionsPackDA in _dbManager.Context.Table<EmotionsPackDA>().Where(g => g.GoalId == _da.Id).ToArray())
                {
                    EmotionsPackDAL emotionsPack = new EmotionsPackDAL(_dbManager);
                    emotionsPack.Load(emotionsPackDA);
                    _tools.Add(emotionsPack);
                }
                foreach (MoneyCalculationDA moneyCalculationDA in _dbManager.Context.Table<MoneyCalculationDA>().Where(g => g.GoalId == _da.Id).ToArray())
                {
                    MoneyCalculationDAL moneyCalculation = new MoneyCalculationDAL(_dbManager);
                    moneyCalculation.Load(moneyCalculationDA);
                    _tools.Add(moneyCalculation);
                }
            });
        }
    }
}